/**
 * Copyright 2014 ABSir's Studio
 * 
 * All right reserved
 *
 * Create on 2014-1-23 下午8:46:00
 */
package com.absir.core.util;

import com.absir.core.kernel.KernelList.Orderable;

/**
 * @author absir
 * 
 */
public class UtilNode<T> {

	/** element */
	private T element;

	/** previous */
	private UtilNode<T> previous;

	/** next */
	private UtilNode<T> next;

	/**
	 * 
	 */
	public UtilNode() {
	}

	/**
	 * @param element
	 */
	public UtilNode(T element) {
		this.element = element;
	}

	/**
	 * @return the element
	 */
	public T getElement() {
		return element;
	}

	/**
	 * @param element
	 *            the element to set
	 */
	public void setElement(T element) {
		this.element = element;
	}

	/**
	 * @return the previous
	 */
	public UtilNode<T> getPrevious() {
		return previous;
	}

	/**
	 * @return the next
	 */
	public UtilNode<T> getNext() {
		return next;
	}

	/**
	 * @param node
	 */
	public void beforeAdd(UtilNode<T> node) {
		if (previous != null) {
			previous.next = node;
		}

		node.previous = previous;
		node.next = this;
		previous = node;
	}

	/**
	 * @param node
	 */
	public void afterAdd(UtilNode<T> node) {
		if (next != null) {
			next.previous = node;
		}

		node.previous = this;
		node.next = next;
		next = node;
	}

	/**
	 * 
	 */
	public void remove() {
		if (previous != null) {
			previous.next = next;
		}

		if (next != null) {
			next.previous = previous;
		}
	}

	/**
	 * @param node
	 */
	public void beforeInsert(UtilNode<T> node) {
		node.remove();
		beforeAdd(node);
	}

	/**
	 * @param node
	 */
	public void afterInsert(UtilNode<T> node) {
		node.remove();
		afterAdd(node);
	}

	/**
	 * @param orderableHeader
	 * @param orderable
	 */
	public static <T extends Orderable> void insertOrderableNode(UtilNode<T> orderableHeader, T orderable) {
		int order = orderable.getOrder();
		UtilNode<T> orderableNodeNext;
		while (true) {
			orderableNodeNext = orderableHeader.getNext();
			if (orderableNodeNext == null || order <= orderableNodeNext.getElement().getOrder()) {
				orderableHeader.afterAdd(new UtilNode<T>(orderable));
				break;
			}

			orderableHeader = orderableNodeNext;
		}
	}

	/**
	 * @param orderableHeader
	 * @param orderable
	 */
	public static <T extends Orderable> void insertOrderableNodeFooter(UtilNode<T> orderableFooter, T orderable) {
		int order = orderable.getOrder();
		UtilNode<T> orderableNodePre;
		while (true) {
			if (orderableFooter.getElement() == null || orderableFooter.getElement().getOrder() <= order) {
				orderableFooter.afterAdd(new UtilNode<T>(orderable));
				break;
			}

			orderableNodePre = orderableFooter.getPrevious();
			if (orderableNodePre == null) {
				orderableFooter.beforeAdd(new UtilNode<T>(orderable));
				break;
			}

			orderableFooter = orderableNodePre;
		}
	}

	/**
	 * @param orderableNode
	 */
	public static <T extends Orderable> void sortOrderableNode(UtilNode<T> orderableNode) {
		int order = orderableNode.getElement().getOrder();
		UtilNode<T> orderableNodeCompare = orderableNode.getNext();
		if (orderableNodeCompare == null || order <= orderableNodeCompare.getElement().getOrder()) {
			orderableNodeCompare = orderableNode;
			T orderableCompare;
			while (true) {
				orderableNodeCompare = orderableNodeCompare.getPrevious();
				orderableCompare = orderableNodeCompare.getElement();
				if (orderableCompare == null || order >= orderableCompare.getOrder()) {
					orderableNodeCompare.afterInsert(orderableNode);
					break;
				}
			}

		} else {
			UtilNode<T> orderableNodeNext = orderableNode.getNext();
			while (true) {
				if (order <= orderableNodeCompare.getElement().getOrder()) {
					orderableNodeCompare.beforeInsert(orderableNode);
					break;
				}

				orderableNodeNext = orderableNodeCompare.getNext();
				if (orderableNodeNext == null) {
					orderableNodeCompare.afterInsert(orderableNode);
					break;
				}

				orderableNodeCompare = orderableNodeNext;
			}
		}
	}

	/**
	 * @param orderableNodeHeader
	 */
	public static <T extends Orderable> void sortOrderableNodeAll(UtilNode<T> orderableNodeHeader) {
		if (orderableNodeHeader.getElement() == null) {
			orderableNodeHeader = orderableNodeHeader.getNext();
			if (orderableNodeHeader == null) {
				return;
			}
		}

		while (orderableNodeHeader != null) {
			sortOrderableNode(orderableNodeHeader);
			orderableNodeHeader = orderableNodeHeader.getNext();
		}
	}
}
